package cn.initcap.algorithm.swing.fractal.vicsek;

import cn.initcap.algorithm.swing.AlgoVisHelper;
import cn.initcap.algorithm.swing.BaseAlgoFrame;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

/**
 * @author initcap
 * @date 8/1/19 10:43 AM
 */
public class AlgoVisualizer {

    private static int DELAY = 40;
    private FractalData data;
    private BaseAlgoFrame frame;

    public AlgoVisualizer(int maxDepth) {

        data = new FractalData(maxDepth);
        int sceneWidth = (int) Math.pow(3, maxDepth);
        int sceneHeight = (int) Math.pow(3, maxDepth);

        EventQueue.invokeLater(() -> {
            frame = new BaseAlgoFrame("Fractal Visualizer", sceneWidth, sceneHeight) {
                @Override
                public void draw(Graphics graphics) {
                    drawFractal((Graphics2D) graphics, 0, 0, sceneWidth, sceneHeight, 0);
                }
            };
            frame.addKeyListener(new AlgoKeyListener());
            new Thread(() -> {
                run();
            }).start();
        });
    }

    public static void main(String[] args) {

        int maxDepth = 6;

        new AlgoVisualizer(maxDepth);
    }

    private void run() {

        setData(data.depth);
    }

    private void setData(int depth) {
        data.depth = depth;

        frame.render(data);
        AlgoVisHelper.pause(DELAY);
    }

    public void addAlgoKeyListener() {
        frame.addKeyListener(new AlgoKeyListener());
    }

    private void drawFractal(Graphics2D g, int x, int y, int w, int h, int depth) {

        if (w <= 1 || h <= 1) {
            AlgoVisHelper.setColor(g, AlgoVisHelper.INDIGO);
            AlgoVisHelper.fillRectangle(g, x, y, Math.max(w, 1), Math.max(h, 1));
            return;
        }

        if (depth == data.depth) {
            AlgoVisHelper.setColor(g, AlgoVisHelper.INDIGO);
            AlgoVisHelper.fillRectangle(g, x, y, w, h);
            return;
        }

        int w3 = w / 3;
        int h3 = h / 3;
        drawFractal(g, x, y, w3, h3, depth + 1);
        drawFractal(g, x + 2 * w3, y, w3, h3, depth + 1);
        drawFractal(g, x + w3, y + h3, w3, h3, depth + 1);
        drawFractal(g, x, y + 2 * h3, w3, h3, depth + 1);
        drawFractal(g, x + 2 * w3, y + 2 * h3, w3, h3, depth + 1);

    }

    private class AlgoKeyListener extends KeyAdapter {

        @Override
        public void keyReleased(KeyEvent event) {
            if (event.getKeyChar() >= '0' && event.getKeyChar() <= '9') {
                int depth = event.getKeyChar() - '0';
                setData(depth);
            }
        }
    }
}